﻿#region Copyright and License Notice
// Copyright (C)2010-2012 - Rob Levine and other contributors
// http://configgen.codeplex.com
// 
// This file is part of ConfigGen.
// 
// ConfigGen is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// 
// ConfigGen is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License and 
// the GNU Lesser General Public License along with ConfigGen.  
// If not, see <http://www.gnu.org/licenses/>.
#endregion
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using ConfigGen.Core.ConfigurationSettings;
using ConfigGen.Utilities.Extensions.System;
using Net.Code.Csv;

namespace ConfigGen.Core.SettingsLoader
{
    /// <summary>
    /// Loads settings collections from comma separated .csv files
    /// </summary>
    public class CsvSettingsLoader : ISettingsLoader
    {
        /// <summary>
        /// Loads and returns the configuration settings
        /// </summary>
        /// <param name="args">Array of arguments for the loader (e.g. filename for excel)</param>
        /// <returns>collection of loaded configuration settings.</returns>
        public MachinesConfigurationCollection LoadSettings(string[] args)
        {
            if (args == null)
            {
                throw new ArgumentNullException("args");
            }

            if (args.Length != 1)
            {
                throw new ArgumentException("One string argument expected", "args");
            }

            var settingsFile = args[0];
            if (settingsFile == null) throw new NullReferenceException("arg[0] settingsFile must not be null");
            if (settingsFile.Length == 0) throw new ArgumentException("The supplied settings file path string cannot be zero length");

            var settingsFileInfo = new FileInfo(settingsFile);
            if (!settingsFileInfo.Exists) throw new FileNotFoundException("The specified settings file path was not found: " + settingsFileInfo.FullName, settingsFileInfo.FullName);

            var machineSettings = new List<MachineConfigurationSettings>();

            string[] headers = null;

            using (var csvDataReader = settingsFileInfo.FullName.ReadFileAsCsv(Encoding.Default))
            {

                while (csvDataReader.Read())
                {
                    if (headers == null)
                    {
                        headers = new string[csvDataReader.FieldCount];
                        for (var i = 0; i < headers.Length; i++)
                        {
                            headers[i] = csvDataReader[i].ToString();
                        }
                    }
                    else
                    {
                        if (headers.Length != csvDataReader.FieldCount)
                        {
                            throw new NotSupportedException("The supplied CSV file was jagged. All rows must contain the same number of fields.");
                        }

                        var values = new string[csvDataReader.FieldCount];
                        bool emptyRow = true;
                        for (var i = 0; i < headers.Length; i++)
                        {
                            string value;

                            var v = csvDataReader[i];
                            if (v == null || v is DBNull)
                            {
                                value = string.Empty;
                            }
                            else
                            {
                                value = v.ToString();
                            }

                            if (!value.IsNullOrEmpty())
                            {
                                emptyRow = false;
                            }

                            values[i] = value;
                        }
                        if (!emptyRow)
                        {
                            var settings = ProcessRow(values, headers);
                            if (settings != null)
                            {
                                machineSettings.Add(settings);
                            }
                        }
                    }
                }
            }

            return new MachinesConfigurationCollection(machineSettings);
        }

        private MachineConfigurationSettings ProcessRow(string[] rowValues, IList<string> columnList)
        {
            var machineName = rowValues[0];
            var configFilePath = rowValues[1];
            if (string.IsNullOrEmpty(machineName) || string.IsNullOrEmpty(configFilePath))
            {
                return null;
            }
            var settings = new List<ConfigurationSetting>();
            for (var i = 2; i < columnList.Count; i++)
            {
                if (rowValues[i].Length > 0)
                    settings.Add(new ConfigurationSetting(columnList[i], rowValues[i]));
            }
            return new MachineConfigurationSettings(machineName, configFilePath, settings);
        }
    }
}
